"""
数据分析和建模过程中 很多时间都要用在数据准备上 加载 , 清理 , 转换 , 以及重塑 这些会占到分析师时间的80% 或更多
处理缺失数据  重复数据  字符串操作  和 其他分析数据转换的工具

# 处理缺失数据  pandas的目标之一就是尽量轻松的处理缺失数据 pandas对象的所有描述性统计默认都不包括缺失数据
# 缺失数据在pandas中呈现的方式有些不完美，但对于大多数用户可以保证功能正常。对于数值数据，pandas使用浮点值NaN（Not a Number）表示缺失数据。我们称其为哨兵值，可以方便的检测出来：

# 创建一个包含字符串的pd.Series对象，其中包含一个NaN值 np.nan 表示缺失数据
string_data = pd.Series(['aardvark', 'artichoke', np.nan, 'avocado'])

# 打印Series对象的内容
print(string_data)

# 检查Series对象中的每个元素是否为NaN，并打印结果
print(string_data.isnull())

# 在pandas中采用R语言中的惯用法 即将缺失值表示NA值 它表示不可用 not available 在统计应用中 NA数据可能是不存在的数据或者虽然存在但是没有观察到 如 数据采集中发生了问题
# 当进行数据清洗以进行分析时 最好直接对缺失数据进行分析 以判断数据采集的问题或缺失数据可能导致的偏差
# python内置的None值在对象数组中也可以做NA

string_data[0] = None # 将string_data[0]的值设置为None
print(string_data.isnull())

# 一些关于缺失数据处理的函数
# dropna
# 根据各标签的值中是否存在缺失数据对轴标签进行过滤，可通过阈值调节
# 对缺失值的容忍度
# fillna
# 用指定值或插值方法（如ffl或ofill)填充缺失数据
# isnull
# 返回一个含有布尔值的对象，这些布尔值表示哪些值是缺失值NA,该对
# 象的类型与源类型一样
# notnull
# isnull的否定式

# 过滤掉缺失数据 可以通过pandas.isnull 或布尔索引的手工方法 但是dropna函数可以更方便的过滤掉缺失数据
# 对于一个Series对象,dropna返回一个仅含非空数据和索引值的Series对象
data = pd.Series([1, NA, 3.5, NA, 7])
print(data.dropna()) # 删除缺失数据
print(data[data.notnull()]) # 删除缺失数据 等价于上一句

# DataFrame对象 希望丢弃全NA 或 NA的行或列  dropna 默认丢弃任何含有缺失值的行
# 导入Pandas库，用于数据处理和分析
import pandas as pd

# 创建一个DataFrame对象，包含一些可能缺失的数据
# 这里演示了如何处理数据中的缺失值
data = pd.DataFrame([[1, 6.5, 3], [1, NA, NA], [NA, NA, NA], [NA, 6.5, 3]])

# 使用dropna方法移除数据框中的缺失值行
# 这一步是为了清理数据，确保后续的数据分析和处理的准确性
cleaned = data.dropna()

# 输出原始数据和清理后的数据，以进行对比
print(data)
print(cleaned)

# 传入how = 'all' 将只丢弃全为NA的行
clean1 = data.dropna(how='all') # 丢弃全为NA的行
print(clean1)

# 传入axis = 1 将丢弃全为NA的列
data[4] = NA
clean2 = data.dropna(axis=1) # 丢弃全为NA的列
print(clean2)

# 丢弃全为NA的列和全为NA的行
clean3 = data.dropna(axis=1,how='all')
print(clean3)

# 过滤DataFrame行的问题涉及时间序列数据 如果只想留下一部分观测数据 可以用thresh参数实现
# 导入pandas库并创建一个DataFrame对象，包含7行3列的随机数数据
df = pd.DataFrame(np.random.randn(7,3))

# 将DataFrame中前4行的第2列数据设置为缺失值（NA）
df.iloc[:4,1] = NA

# 将DataFrame中前2行的第3列数据设置为缺失值（NA）
df.iloc[:2,2] = NA

# 打印原始DataFrame，包含缺失值
print(df)

# 打印删除包含任何缺失值的行后的DataFrame
print(df.dropna())

# 打印至少有2个非缺失值的行的DataFrame，这样可以保留至少有2个有效数据的行
print(df.dropna(thresh=2))

# 填充缺失值 使用fillna方法是最主要的函数 一个常数调用fillna 就会将缺失值替换为那个常数值
print(df.fillna(0)) # 将缺失值填充为0

# 通过一个字典调用fillna方法 就可以实现对不同的列填充不同的值
a = df.fillna({1:0,2:2}) # 将第一列的缺失值填充为0，第二列的缺失值填充为2
print(a)

# fillna 默认会返回新对象 但可以对现象进行就地修改
_ = df.fillna(0,inplace=True) # 对df进行就地修改
print(df)

# 对reindexing 有效的那些插值方法也可以用于fillna
# 导入pandas库并创建一个包含随机数的DataFrame
df = pd.DataFrame(np.random.randn(6,3))

# 将索引2及以后的第二列值设置为NA
df.iloc[2:,1] = NA

# 将索引4及以后的第三列值设置为NA
df.iloc[4:,2] = NA

# 打印原始DataFrame
print(df)

# 使用前向填充方法填充NA值，并打印结果 (前向填充) 复制上一个值的数据
print(df.fillna(method='ffill'))

# 使用前向填充方法填充NA值，但限制最大填充数量为2，并打印结果
print(df.fillna(method='ffill',limit=2))

data = pd.Series([1,NA,7,NA,3],index=list('abcde'))
data.fillna(data.mean()) # 用均值填充缺失值
print(data)

# fillna的参数
# value
# 用于填充缺失值的标量值或字典对象
# method
# 插值方式。如果函数调用时未指定其他参数的话，默认为“ffill”
# axis
# 待填充的轴，默认axis=0
# inplace
# 修改调用者对象而不产生副本
# limit
# (对于前向和后向填充)可以连续填充的最大数量

# 移除重复数据
data = pd.DataFrame({'k1':['one','two']*3+['two'],'k2':[1,1,2,3,3,4,4]})
# print(data)

# DataFrame的duplicated方法返回一个布尔型Series 表示各行是否是重复行 或者是前面出现过的行
# print(data.duplicated())

# drop_duplicates方法移除重复行 返回一个DataFrame对象 重复的数组会标位False
print(data.drop_duplicates())

# 这两个方法默认会判断全部列,也可以指定部分列进行重复项判断 假设有一列值 只希望根据k1列过滤重复项
data['v1'] = range(7)
print(data.drop_duplicates(['k1'])) # 根据k1列过滤重复项

# duplicated 和 drop_duplicates 默认保留的是第一个出现的值组合 , 如果想保留最后一个出现的值组合 可以设置keep='last'
print(data.drop_duplicates(['k1','k2'],keep='last'))

data = pd.DataFrame({'food': ['bacon', 'pulled pork', 'bacon','Pastrami', 'corned beef', 'Bacon','pastrami', 'honey ham', 'nova lox'],'ounces': [4, 3, 12, 6, 7.5, 8, 3, 5, 6]})

print(data)

# 添加一列表示该肉类食物来源的动物类型 先编写一个不同肉类到动物的映射
meat_to_animal = {
    'bacon': 'pig',
    'pulled pork': 'pig',
    'pastrami': 'cow',
    'corned beef': 'cow',
    'honey ham': 'pig',
    'nova lox': 'salmon'
}

# Series的map方法可以接受一个函数或含有映射关系的字典型对象，但是这里有一个小问题，即有些肉类的首字母大写了，而另一些则没有。因此，我们还需要使用Series的str.lower方法，将各个值转换为小写：
lowercased = data['food'].str.lower()
print(lowercased)

data['animal'] = lowercased.map(meat_to_animal)
print(data)

# 使用一个工作函数来处理数据
data['food'].map(lambda x: meat_to_animal[x.lower()])

# 替换值 利用fillna方法填充缺失数据可以看做值替换的一种特殊情况 map可用于修改对象的数据子集
# replace 方法 替换值
data = pd.Series([1., -999., 2., -999., -1000., 3.])
print(data)

# -999 值表示一个缺失数据的标记值 要替换成pandas 的NA值  可以利用replace方法 产生一个新的Series 除非传入inplace=True
data.replace(-999, np.nan)
print(data)

# 希望一次性替换多个值 可以传入一个由待替换值组成的列表以及一个替换值
data.replace([-999,-1000],np.nan)

# 每个值有不同的替换值 可以传递一个替换列表
data.replace([-999,-1000],[np.nan,0])

# 传入的参数可以是字典
data.replace({-999:np.nan,-1000:0})
# data.replace方法与data.str.replace不同，后者做的是字符串的元素级替换

# 重命名轴索引 轴索引可以通过函数或映射进行转换 从而得到一个新的不同标签的对象,轴还可以就地修改
data = pd.DataFrame(np.arange(12).reshape((3, 4)),
                    index=['Ohio', 'Colorado', 'New York'],
                    columns=['one', 'two', 'three', 'four'])

# 轴索引的 map 方法
# 定义一个lambda函数，将输入的字符串的前四个字符转换为大写
transform = lambda x: x[:4].upper()

# 使用定义的lambda函数transform对data的索引进行映射处理
# 这里假设data是一个具有索引属性的对象，如DataFrame或Series
print(data.index.map(transform))

# 将其赋值给index 可以对DataFrame进行修改
data.index = data.index.map(transform)
print(data)

# 要想创建数据集的转换板 而不是修改原始数据 可以使用rename方法
data.rename(index=str.title, columns=str.upper)

# rename 可以结合字典型对象实现对部分轴标签的更新
data.rename(index={'OHIO': 'INDIANA'},
            columns={'three': 'peekaboo'})

# rename方法默认是返回一个修改后的副本，如果想要修改原始数据，可以设置inplace=True
data.rename(index={'OHIO': 'INDIANA'}, inplace=True)
print(data)

# 离散化和面元划分  连续数据常常被离散化或拆分为 面元(bin)
# 有一组人员数据 希望划分为不同的年龄组
ages = [20, 22, 25, 27, 21, 23, 37, 31, 61, 45, 41, 32]

# 将这些数据划分为“18到25”、“26到35”、“35到60”以及“60以上”几个面元 要实现该功能 需要使用pandas的cut函数
bins = [18, 25, 35, 60, 100]

# 使用pandas的cut函数对ages列表中的年龄数据进行分段
cats = pd.cut(ages, bins)

print(cats)

# pandas返回的是一个特殊的Categorical对象，它表示了数据被分段，并且每个面元都有相应的计数,结果展示了pandas.cut划分的面元
# 可以将其看做一组表示面元名称的字符串 底层含有一个表示不同分类名称的类型数组,以及一个codes 属性中的年龄数据的标签
# 打印cats变量的编码值，这些编码值代表了类别数据的内部表示
print(cats.codes)
# 打印cats变量的类别值，展示了每个编码值对应的类别标签
print(cats.categories)
# 计算并打印cats变量中每个类别值的出现次数，使用pd.value_counts函数
print(pd.value_counts(cats))

# pd.value_counts(cats)是pandas.cut结果的面元计数
# 跟 区间 的数学符号一样 圆括号表示开端,方括号则表示闭端(包括) 哪边是闭端可以通过right=False来控制
pd.cut(ages, [18, 26, 35, 61, 100], right=False) # 输出结果为[18, 26) [26, 35) [35, 61) [61, 100]]]]

# 传递一个列表或数组到labels  设置自己的面元名称
group_name = ['Youth', 'YoungAdult', 'MiddleAged', 'Senior']
pd.cut(ages, bins, labels=group_name)
# 如果向cut传入的是面元的数量而不是确切的面元边界 则会根据数据的最小值和最大值计算等长面元
# 生成20个0到1之间的随机浮点数，存储在data变量中
data = np.random.rand(20)

# 将data中的数据切成4个等宽的区间，precision参数指定了结果的精度为2
pd.cut(data, 4, precision=2)

# qcut是一个类似于cut的函数 可以根据样本分位数对数据进行面元划分 根据数据的分布情况 cut可能无法使各个面元中含有相同数量的数据点
# 而qcut则根据样本分位数进行划分，因此可以确保每个面元中包含的数据点数量基本相同
# 生成1000个符合标准正态分布的随机数
data = np.random.randn(1000)

# 将数据分为4个等大小的区间
# 这里的目的是对数据进行分桶，以便后续分析
cat = pd.qcut(data, 4)

# 输出分桶结果
print(cat)

# 计算并输出每个区间的元素数量
# 这一步是为了检查每个区间是否均匀分布了数据
print(pd.value_counts(cat))

cat1 = pd.qcut(data,[0,0.1,0.5,0.9,1.])
print(cat1)

# 检测和过滤异常值
# 过滤或变换异常值outlier 在很大程度上就是运用数组运算 含有正态分布数据的DataFrame
# 创建一个包含随机数据的DataFrame，用于后续的数据分析
data = pd.DataFrame(np.random.randn(1000, 4))

# 打印DataFrame的基本统计信息，包括均值、标准差、最小值、最大值等
# print(data.describe())

# 假设找出某列中绝对值大小超过3的值
col = data[2]

# 使用布尔索引过滤掉绝对值大于3的行
col3 = col[np.abs(col) > 3]
print(col3)

# 选出全部含有 超过3 或 -3的值 的行  在 DataFrame中中使用any方法
col4 = data[(np.abs(data) > 3).any(1)]

# 可以将值限制在区间 -3到3 以内
# 对数据进行缩放，将所有绝对值大于3的数据点设置为3或-3，避免数据范围过宽
data[np.abs(data)>3] = np.sign(data)*3

# 打印缩放后数据的基本统计信息，以便检查数据处理效果
print(data.describe())

# 根据数据的值是正还是负 np.sign(data) 可以生成1和-1
np.sign(data).head()

# 排列和随机采样
# 利用numpy.random.permutation函数可以轻松实现对Series或DataFrame的列的排列工作（permuting，随机重排序）。通过需要排列的轴的长度调用permutation，可产生一个表示新顺序的整数数组：

# 创建一个包含5行4列的DataFrame，数据为0到19的整数
df = pd.DataFrame(np.arange(5 * 4).reshape((5, 4)))

# 生成一个包含5个元素的随机排列，用于后续可能的数据采样
sampler = np.random.permutation(5)
print(sampler)

# 基于iloc的索引操作或take函数中使用该数组
# 打印整个数据框df，用于查看数据结构和内容
print(df)

# 使用sampler对数据框df进行采样，并打印采样结果
# 这里的sampler应该是一个采样器对象，用于指定如何从数据框中抽取样本
print(df.take(sampler))
# 使用sample 方法
print(df.sample(n=3))

# 通过替换的方式产生样本 允许重复选择 可以传递 replace=True到 sample
# 创建一个pandas Series对象，包含一些整数
# 这些整数代表可供选择的项
choices = pd.Series([5, 7, -1, 6, 4])

# 从choices中随机抽取10个样本，允许重复抽取
# 这种抽样方法可以用于模拟随机选择过程
draws = choices.sample(n=10, replace=True)

# 输出抽取的结果
print(draws)

# 计算指标/哑变量
# 常用于统计建模或机器学习的转换方式是: 将分类变量 转换为 哑变量 或指标变量
# 如果DataFrame的某一列中含有k个不同的值，则可以派生出一个k列矩阵或DataFrame（其值全为1和0）。pandas有一个get_dummies函数可以实现该功能（其实自己动手做一个也不难）。使用之前的一个DataFrame例子
# 创建一个DataFrame对象，包含两列数据
# 'key' 列包含类别标签，'data1' 列包含数据
df = pd.DataFrame({'key': ['b', 'b', 'a', 'c', 'a', 'b'],'data1': range(6)})

# 使用pd.get_dummies将'key'列的类别标签转换为独热编码（One-Hot Encoding）
# 这样做是为了在机器学习模型中处理类别数据，避免模型对类别标签的数值大小产生误解
print(pd.get_dummies(df['key']))

# 字符串操作  字符串对象方法 许多字符串处理和脚本 内置的字符串方法已经满足要求,以逗号分隔的字符串可以用split拆分成手段
val = 'a,b, guido'
# 以逗号分隔的字符串可以拆分成列表
print(val.split(',')) # 输出结果为['a', 'b', ' guido']

# split常与strip一起使用 以去除空白符 包含换行符
pieces = [x.strip() for x in val.split(',')]
print(pieces)

# 利用加法 这些子字符串以双冒号分隔符的形式连接起来
first, second, third = pieces
print(first+ '::' + second + '::' + third)

# 这种方式不是很实用 一种更快更符合python风格的方式 想字符串 "::"的join方法传入一个列表或元组
print('::'.join(pieces))

# 检测子串的最佳方式是利用 python的in关键字 还可以使用index和find
print('guido' in val) # 检测子串是否在字符串中
print(val.index(',')) # 返回子串在字符串中的索引位置
print(val.find(':')) # 返回子串在字符串中的索引位置

# 注意find和index的区别 如果找不到字符串 index将会引发一个异常而不是返回-1
# print(val.index(':'))

# count可以返回指定子串的出现次数
print(val.count(',')) # 返回子串在字符串中出现的次数

# replace 用于将指定模式替换为另一个模式,通过传入空字符串 也常用于删除模式
val.replace(',', '::') # 返回替换后的字符串
val.replace(',', '') #删除逗号

# python内置的字符串方法
count
返回子串在字符串中的出现次数（非重叠）
endswith、startswith
如果字符串以某个后缀结尾（以某个前缀开头），则返回True
join
将字符串用作连接其他字符串序列的分隔符
index
如果在字符串中找到子串，则返回子串第一个字符所在的位
置。如果没有找到，则引发ValueError。
find
如果在字符串中找到子串，则返回第一个发现的子串的第一个
字符所在的位置。如果没有找到，则返回一1
rfind
如果在字符串中找到子串，则返回最后一个发现的子串的第一
个字符所在的位置。如果没有找到，则返回一1
replace
用另一个字符串替换指定子串
strip、rstrip、Istrip
去除空白符（包括换行符)。相当于对各个元素执行x.strip()
(以及rstrip、Istrip)。
译注10
split
通过指定的分隔符将字符串拆分为一组子串
lower、upper
分别将字母字符转换为小写或大写
ljust、rjust
用空格（或其他字符)填充字符串的空白侧以返回符合最低宽
度的字符串

casefold 将字符转换为小写 并将任何特别区别的变量字符组合转换成一个通用可比较形式

# 正则表达式 正则表达式提供了一种灵活的在文本中搜索或匹配（通常比前者复杂）字符串模式的方式。正则表达式，常称作regex，是根据正则表达式语言编写的字符串。Python内置的re模块负责对字符串应用正则表达式。
# re模块的函数可以分为三个大类：模式匹配、替换以及拆分。
# 想要拆分一个字符串,分隔符为数量不定的一组空白符 制表符,换行符,空格符 描述一个或多个空白符的regex是\s
text = "foo    bar\t baz  \tqux"
print(re.split('\s+', text)) # 输出结果为['foo', 'bar', 'baz', 'qux'] 拆分字符串
# 调用re.split('\s+',text)时,正则表达式会先被编译,然后再text上调用其split方法 ,可以用re.compile()自己编译regex以得到一个可重用的regex对象
regex = re.compile('\s+') # 编译正则表达式
print(regex.split(text)) # 输出结果为['foo', 'bar', 'baz', 'qux']

# 如果只希望得到匹配regex的所有模式 则可以使用re.findall()
print(regex.findall(text)) # findall()返回一个列表，包含所有匹配的子串

# 如果打算对许多字符串应用同一条正则表达式，强烈建议通过re.compile创建regex对象。这样将可以节省大量的CPU时间。
# match和search 跟findall功能类似  findall 返回的是字符串中所有的匹配项,而search则只返回第一个匹配项
# match只匹配字符串的首部
# 有一段文本以及一条能够识别大部分电子邮件地址的正则表达式

# 定义一个正则表达式模式，用于匹配电子邮件地址
pattern = r'[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}'
# 编译正则表达式，忽略大小写
regex = re.compile(pattern, flags=re.IGNORECASE)
# 对text使用findall 将得到一组电子邮件地址
print(regex.findall(text))
# search返回的是文本中第一个电子邮件地址 以特殊的匹配项对象形式返回  匹配项对象只能告诉我们模式在原字符串中的起始和结束位置
m = regex.search(text)
# 打印匹配项对象、起始位置、结束位置和匹配到的文本
print(m, m.start(), m.end(), m.group())

# regex.match则将返回None 因为它只匹配出现在字符串开头的模式
print(regex.match(text))

# sub方法可以将匹配到模式替换为指定字符串 ,并返回所得到的新字符串
print(regex.sub(r'REDACTED', text))

# 假设你不仅想要找出电子邮件地址，还想将各个地址分成3个部分：用户名、域名以及域后缀。要实现此功能，只需将待分段的模式的各部分用圆括号包起来即可：

text = '''Dave dave@google.com
Steve steve@gmail.com
Rob rob@gmail.com
Ryan ryan@yahoo.com
'''

# 定义一个正则表达式模式，用于匹配电子邮件地址
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'

# 编译正则表达式，忽略大小写，以便于在任何文本中匹配电子邮件地址
regex = re.compile(pattern, flags=re.IGNORECASE)

# 使用编译的正则表达式匹配一个电子邮件地址，验证模式是否正确
m = regex.match('wesm@bright.net')

# 打印匹配到的电子邮件地址的各个部分
print(m.groups())

# 在给定的文本中查找所有匹配的电子邮件地址并打印
print(regex.findall(text))

# sub还能通过诸如 \1 \2之类的特殊符号访问各匹配项中的分组 符号\1对应第一个匹配的组 \2对应第二个匹配的组
print(regex.sub(r'Username: \1, Domain: \2, Suffix: \3', text))

# findall、finditer
# 返回字符串中所有的非重叠匹配模式。findalli返回的是由所有模式
# 组成的列表，而finditer.则通过一个迭代器逐个返回
# match
# 从字符串起始位置匹配模式，还可以对模式各部分进行分组。如果
# 匹配到模式，则返回一个匹配项对象，否则返回None
# search
# 扫描整个字符串以匹配模式。如果找到则返回一个匹配项对象。跟
# match不同，其匹配项可以位于字符串的任意位置，而不仅仅是起
# 始处
# split
# 根据找到的模式将字符串拆分为数段
# sub、subn
# 将字符串中所有的(sub)或前n个（(subn)模式替换为指定表达
# 式译注12。
# 在替换字符串中可以通过1、12等符号表示各分组项

"""
import numpy as np
import pandas as pd
import re

from jupyter_core.version import pattern
from markdown_it.parser_core import ParserCore
from numpy import nan as NA

# pandas的矢量化字符串函数 字符串规整化工作 含有字符串的列有时还含有缺失数据
# 创建一个字典，包含人名作为键，电子邮件地址作为值，其中Wes的值为np.nan，表示缺失值
data = {'Dave': 'dave@google.com', 'Steve': 'steve@gmail.com','Rob': 'rob@gmail.com', 'Wes': np.nan}
# 将字典转换为pandas的Series对象，便于后续的数据处理和分析
data = pd.Series(data)
# 输出Series对象，查看数据结构和内容
print(data)
# 检查Series中的缺失值，isnull方法会返回一个布尔数组，指示每个元素是否为缺失值
print(data.isnull)
# 通过data.map，所有字符串和正则表达式方法都能被应用于（传入lambda表达式或其他函数）各个值，但是如果存在NA（null）就会报错
# 因此，需要使用Series的str属性来避免这个问题
# Series有一些能够跳过NA值的面向数组方法，进行字符串操作。通过Series的str属性即可访问这些方法
# 例如，我们可以通过str.contains检查各个电子邮件地址是否含有”gmail”：
print(data.str.contains('gmail')) # 返回一个布尔数组，指示每个元素是否包含'gmail'

# 使用正则表达式 还可以加入任意re选项 如IGNORECASE
# 这里定义了一个正则表达式模式，用于匹配电子邮件地址
pattern = r'([A-Z0-9._%+-]+)@([A-Z0-9.-]+)\.([A-Z]{2,4})'
# 使用str.findall方法，根据正则表达式查找所有匹配的子串，flags参数可以指定正则表达式的附加选项，如忽略大小写
data.str.findall(pattern, flags=re.IGNORECASE)

# 实现矢量化的元素获取操作 要么使用str.get,要么str属性上使用索引
# 使用str.match方法，根据正则表达式对每个元素进行匹配，返回一个布尔数组
match = data.str.match(pattern, flags=re.IGNORECASE)
# 使用str.get方法，获取每个元素匹配结果的指定组，这里获取第一个括号内的内容
data.str.get(1)
# 通过索引操作，获取每个元素的第一个字符
data.str[0]
# 通过切片操作，获取每个元素的前五个字符
data.str[:5]


# cat
# 实现元素级的字符串连接操作，可指定分隔符
# count
# 返回表示个字符串是否含有指定模式的布尔型数组
# extract
# 使用带分组的正则表达式从字符串Series提取一个或多个字符串，结果是一个DataFrame,.
# 每组有一列
# endswith
# 相当于对每个元素执行x.endswith(pattern)
# startswith
# 相当于对每个元素执行x.startswith(pattern)
# findall
# 计算各字符串的模式列表
# get
# 获取各元素的第ⅰ个字符
# isalnum
# 相当于内置的str.alnum
# isalpha
# 相当于内置的str.isalpha
# isdecimal
# 相当于内置的str.isdecimal
# isdigit
# 相当于内置的str.isdigit
# islower
# 相当于内置的str.islower
# isnumeric
# 相当于内置的str.isnumeric
# isupper
# 相当于内置的str.isupper
# join
# 根据指定的分隔符将Series中各元素的字符串连接起来
# len
# 计算各字符串的长度
# lower,upper
# 转换大小写。相当于对各个元素执行x.lower(0或x.upper(0
# match
# 根据指定的正则表达式对各个元素执行re.match,返回匹配的组为列表
# pad
# 在字符串的左边、右边或两边添加空白符
# center
# 相当于pad(side='both)
# repeat
# 重复值。例如，s.str.repeat(3)相当于对各个字符串执行x*3
# replace
# 用指定字符串替换找到的模式
# slice
# 对Series中的各个字符串进行子串截取
# split
# 根据分隔符或正则表达式对字符串进行拆分
# strip
# 去除两边的空白符，包括新行
# rstrip
# 去除右边的空白符
# Istrip
# 去除左边的空白符



if __name__ == '__main__':
    pass
